home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / dev / gcc / gcc270_src.lha / gcc-2.7.0-amiga / config / ns32k / ns32k.c < prev    next >
C/C++ Source or Header  |  1995-06-15  |  21KB  |  874 lines

  1. /* Subroutines for assembler code output on the NS32000.
  2.    Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21. /* Some output-actions in ns32k.md need these.  */
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33.  
  34. #ifdef OSF_OS
  35. int ns32k_num_files = 0;
  36. #endif
  37.  
  38. void
  39. trace (s, s1, s2)
  40.      char *s, *s1, *s2;
  41. {
  42.   fprintf (stderr, s, s1, s2);
  43. }
  44.  
  45. /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
  46.  
  47. int
  48. hard_regno_mode_ok (regno, mode)
  49.      int regno;
  50.      enum machine_mode mode;
  51. {
  52.   switch (mode)
  53.     {
  54.     case QImode:
  55.     case HImode:
  56.     case PSImode:
  57.     case SImode:
  58.     case PDImode:
  59.     case VOIDmode:
  60.     case BLKmode:
  61.       if (regno < 8 || regno == 16 || regno == 17)
  62.     return 1;
  63.       else
  64.     return 0;
  65.  
  66.     case DImode:
  67.       if (regno < 8 && (regno & 1) == 0)
  68.     return 1;
  69.       else
  70.     return 0;
  71.  
  72.     case SFmode:
  73.     case SCmode:
  74.       if (TARGET_32081)
  75.     {
  76.       if (regno < 16)
  77.         return 1;
  78.       else
  79.         return 0;
  80.     }
  81.       else
  82.     {
  83.       if (regno < 8)
  84.         return 1;
  85.       else 
  86.         return 0;
  87.     }
  88.  
  89.     case DFmode:
  90.     case DCmode:
  91.       if ((regno & 1) == 0)
  92.     {    
  93.       if (TARGET_32081)
  94.         {
  95.           if (regno < 16)
  96.         return 1;
  97.           else
  98.         return 0;
  99.         }
  100.       else
  101.         {
  102.           if (regno < 8)
  103.         return 1;
  104.           else
  105.         return 0;
  106.         }
  107.     }
  108.       else
  109.     return 0;
  110.     }
  111.  
  112.   /* Used to abort here, but simply saying "no" handles TImode
  113.      much better.  */
  114.   return 0;
  115. }
  116.  
  117. /* ADDRESS_COST calls this.  This function is not optimal
  118.    for the 32032 & 32332, but it probably is better than
  119.    the default. */
  120.  
  121. int
  122. calc_address_cost (operand)
  123.      rtx operand;
  124. {
  125.   int i;
  126.   int cost = 0;
  127.   
  128.   if (GET_CODE (operand) == MEM)
  129.     cost += 3;
  130.   if (GET_CODE (operand) == MULT)
  131.     cost += 2;
  132. #if 0
  133.   if (GET_CODE (operand) == REG)
  134.     cost += 1;            /* not really, but the documentation
  135.                    says different amount of registers
  136.                    shouldn't return the same costs */
  137. #endif
  138.   switch (GET_CODE (operand))
  139.     {
  140.     case REG:
  141.     case CONST:
  142.     case CONST_INT:
  143.     case CONST_DOUBLE:
  144.     case SYMBOL_REF:
  145.     case LABEL_REF:
  146.     case POST_DEC:
  147.     case PRE_DEC:
  148.       break;
  149.     case MULT:
  150.     case MEM:
  151.     case PLUS:
  152.       for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
  153.     {
  154.       cost += calc_address_cost (XEXP (operand, i));
  155.     }
  156.     default:
  157.       break;
  158.     }
  159.   return cost;
  160. }
  161.  
  162. /* Return the register class of a scratch register needed to copy IN into
  163.    or out of a register in CLASS in MODE.  If it can be done directly,
  164.    NO_REGS is returned.  */
  165.  
  166. enum reg_class
  167. secondary_reload_class (class, mode, in)
  168.      enum reg_class class;
  169.      enum machine_mode mode;
  170.      rtx in;
  171. {
  172.   int regno = true_regnum (in);
  173.  
  174.   if (regno >= FIRST_PSEUDO_REGISTER)
  175.     regno = -1;
  176.  
  177.   /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
  178.      into anything.  */
  179.   if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
  180.     return NO_REGS;
  181.  
  182.   /* Constants, memory, and FP registers can go into FP registers.  */
  183.   if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
  184.     return NO_REGS;
  185.  
  186. #if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
  187.      so it's cleaner to use PREFERRED_RELOAD_CLASS
  188.      to make the right things happen.  */
  189.   if (regno >= 16 && class == GEN_AND_MEM_REGS)
  190.     return NO_REGS;
  191. #endif
  192.  
  193.   /* Otherwise, we need GENERAL_REGS. */
  194.   return GENERAL_REGS;
  195. }
  196. /* Generate the rtx that comes from an address expression in the md file */
  197. /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
  198.    scale must be converted from an exponent (from ASHIFT) to a
  199.    multiplier (for MULT). */
  200. rtx
  201. gen_indexed_expr (base, index, scale)
  202.      rtx base, index, scale;
  203. {
  204.   rtx addr;
  205.  
  206.   /* This generates an invalid addressing mode, if BASE is
  207.      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
  208.   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
  209.     base = gen_rtx (MEM, SImode, base);
  210.   addr = gen_rtx (MULT, SImode, index,
  211.           gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
  212.   addr = gen_rtx (PLUS, SImode, base, addr);
  213.   return addr;
  214. }
  215.  
  216. /* Return 1 if OP is a valid operand of mode MODE.  This
  217.    predicate rejects operands which do not have a mode
  218.    (such as CONST_INT which are VOIDmode).  */
  219. int
  220. reg_or_mem_operand (op, mode)
  221.      register rtx op;
  222.      enum machine_mode mode;
  223. {
  224.   return (GET_MODE (op) == mode
  225.       && (GET_CODE (op) == REG
  226.           || GET_CODE (op) == SUBREG
  227.           || GET_CODE (op) == MEM));
  228. }
  229.  
  230. /* Return the best assembler insn template
  231.    for moving operands[1] into operands[0] as a fullword.  */
  232.  
  233. static char *
  234. singlemove_string (operands)
  235.      rtx *operands;
  236. {
  237.   if (GET_CODE (operands[1]) == CONST_INT
  238.       && INTVAL (operands[1]) <= 7
  239.       && INTVAL (operands[1]) >= -8)
  240.     return "movqd %1,%0";
  241.   return "movd %1,%0";
  242. }
  243.  
  244. char *
  245. output_move_double (operands)
  246.      rtx *operands;
  247. {
  248.   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
  249.   rtx latehalf[2];
  250.  
  251.   /* First classify both operands.  */
  252.  
  253.   if (REG_P (operands[0]))
  254.     optype0 = REGOP;
  255.   else if (offsettable_memref_p (operands[0]))
  256.     optype0 = OFFSOP;
  257.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  258.     optype0 = PUSHOP;
  259.   else
  260.     optype0 = RNDOP;
  261.  
  262.   if (REG_P (operands[1]))
  263.     optype1 = REGOP;
  264.   else if (CONSTANT_P (operands[1])
  265.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  266.     optype1 = CNSTOP;
  267.   else if (offsettable_memref_p (operands[1]))
  268.     optype1 = OFFSOP;
  269.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  270.     optype1 = PUSHOP;
  271.   else
  272.     optype1 = RNDOP;
  273.  
  274.   /* Check for the cases that the operand constraints are not
  275.      supposed to allow to happen.  Abort if we get one,
  276.      because generating code for these cases is painful.  */
  277.  
  278.   if (optype0 == RNDOP || optype1 == RNDOP)
  279.     abort ();
  280.  
  281.   /* Ok, we can do one word at a time.
  282.      Normally we do the low-numbered word first,
  283.      but if either operand is autodecrementing then we
  284.      do the high-numbered word first.
  285.  
  286.      In either case, set up in LATEHALF the operands to use
  287.      for the high-numbered word and in some cases alter the
  288.      operands in OPERANDS to be suitable for the low-numbered word.  */
  289.  
  290.   if (optype0 == REGOP)
  291.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  292.   else if (optype0 == OFFSOP)
  293.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  294.   else
  295.     latehalf[0] = operands[0];
  296.  
  297.   if (optype1 == REGOP)
  298.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  299.   else if (optype1 == OFFSOP)
  300.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  301.   else if (optype1 == CNSTOP)
  302.     split_double (operands[1], &operands[1], &latehalf[1]);
  303.   else
  304.     latehalf[1] = operands[1];
  305.  
  306.   /* If insn is effectively movd N(sp),tos then we will do the
  307.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  308.      for the low word as well, to compensate for the first decrement of sp.
  309.      Given this, it doesn't matter which half we do "first".  */
  310.   if (optype0 == PUSHOP
  311.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  312.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  313.     operands[1] = latehalf[1];
  314.  
  315.   /* If one or both operands autodecrementing,
  316.      do the two words, high-numbered first.  */
  317.   else if (optype0 == PUSHOP || optype1 == PUSHOP)
  318.     {
  319.       output_asm_insn (singlemove_string (latehalf), latehalf);
  320.       return singlemove_string (operands);
  321.     }
  322.  
  323.   /* If the first move would clobber the source of the second one,
  324.      do them in the other order.  */
  325.  
  326.   /* Overlapping registers.  */
  327.   if (optype0 == REGOP && optype1 == REGOP
  328.       && REGNO (operands[0]) == REGNO (latehalf[1]))
  329.     {
  330.       /* Do that word.  */
  331.       output_asm_insn (singlemove_string (latehalf), latehalf);
  332.       /* Do low-numbered word.  */
  333.       return singlemove_string (operands);
  334.     }
  335.   /* Loading into a register which overlaps a register used in the address.  */
  336.   else if (optype0 == REGOP && optype1 != REGOP
  337.        && reg_overlap_mentioned_p (operands[0], operands[1]))
  338.     {
  339.       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
  340.       && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
  341.     {
  342.       /* If both halves of dest are used in the src memory address,
  343.          load the destination address into the low reg (operands[0]).
  344.          Then it works to load latehalf first.  */
  345.       rtx xops[2];
  346.       xops[0] = XEXP (operands[1], 0);
  347.       xops[1] = operands[0];
  348.       output_asm_insn ("addr %a0,%1", xops);
  349.       operands[1] = gen_rtx (MEM, DImode, operands[0]);
  350.       latehalf[1] = adj_offsettable_operand (operands[1], 4);
  351.       /* The first half has the overlap, Do the late half first.  */
  352.       output_asm_insn (singlemove_string (latehalf), latehalf);
  353.       /* Then clobber.  */
  354.       return singlemove_string (operands);
  355.     }
  356.       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
  357.     {
  358.       /* The first half has the overlap, Do the late half first.  */
  359.       output_asm_insn (singlemove_string (latehalf), latehalf);
  360.       /* Then clobber.  */
  361.       return singlemove_string (operands);
  362.     }
  363.     }
  364.  
  365.   /* Normal case.  Do the two words, low-numbered first.  */
  366.  
  367.   output_asm_insn (singlemove_string (operands), operands);
  368.  
  369.   operands[0] = latehalf[0];
  370.   operands[1] = latehalf[1];
  371.   return singlemove_string (operands);
  372. }
  373.  
  374. int
  375. check_reg (oper, reg)
  376.      rtx oper;
  377.      int reg;
  378. {
  379.   register int i;
  380.  
  381.   if (oper == 0)
  382.     return 0;
  383.   switch (GET_CODE(oper))
  384.     {
  385.     case REG:
  386.       return (REGNO(oper) == reg) ? 1 : 0;
  387.     case MEM:
  388.       return check_reg(XEXP(oper, 0), reg);
  389.     case PLUS:
  390.     case MULT:
  391.       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
  392.     }
  393.   return 0;
  394. }
  395.  
  396. /* Returns 1 if OP contains a global symbol reference */
  397.  
  398. int
  399. global_symbolic_reference_mentioned_p (op, f)
  400.      rtx op;
  401.      int f;
  402. {
  403.   register char *fmt;
  404.   register int i;
  405.  
  406.   if (GET_CODE (op) == SYMBOL_REF)
  407.     {
  408.       if (! SYMBOL_REF_FLAG (op))
  409.     return 1;
  410.       else
  411.         return 0;
  412.     }
  413.   else if (f && GET_CODE (op) != CONST)
  414.     return 0;
  415.  
  416.   fmt = GET_RTX_FORMAT (GET_CODE (op));
  417.   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
  418.     {
  419.       if (fmt[i] == 'E')
  420.     {
  421.       register int j;
  422.  
  423.       for (j = XVECLEN (op, i) - 1; j >= 0; j--)
  424.         if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
  425.           return 1;
  426.     }
  427.       else if (fmt[i] == 'e' 
  428.            && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
  429.     return 1;
  430.     }
  431.  
  432.   return 0;
  433. }
  434.  
  435.  
  436. /* PRINT_OPERAND is defined to call this function,
  437.    which is easier to debug than putting all the code in
  438.    a macro definition in ns32k.h.  */
  439.  
  440. void
  441. print_operand (file, x, code)
  442.      FILE *file;
  443.      rtx x;
  444.      char code;
  445. {
  446.   if (code == '$')
  447.     PUT_IMMEDIATE_PREFIX (file);
  448.   else if (code == '?')
  449.     PUT_EXTERNAL_PREFIX (file);
  450.   else if (GET_CODE (x) == REG)
  451.     fprintf (file, "%s", reg_names[REGNO (x)]);
  452.   else if (GET_CODE (x) == MEM)
  453.     {
  454.       rtx tmp = XEXP (x, 0);
  455.       output_address (XEXP (x, 0));
  456.     }
  457.   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
  458.     {
  459.       if (GET_MODE (x) == DFmode)
  460.     { 
  461.       union { double d; int i[2]; } u;
  462.       u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
  463.       PUT_IMMEDIATE_PREFIX(file);
  464. #ifdef SEQUENT_ASM
  465.       /* Sequent likes it's floating point constants as integers */
  466.       fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
  467. #else
  468. #ifdef ENCORE_ASM
  469.       fprintf (file, "0f%.20e", u.d); 
  470. #else
  471.       fprintf (file, "0d%.20e", u.d); 
  472. #endif
  473. #endif
  474.     }
  475.       else
  476.     { 
  477.       union { double d; int i[2]; } u;
  478.       u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
  479.       PUT_IMMEDIATE_PREFIX (file);
  480. #ifdef SEQUENT_ASM
  481.       /* We have no way of winning if we can't get the bits
  482.          for a sequent floating point number.  */
  483. #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
  484.       abort ();
  485. #endif
  486.       {
  487.         union { float f; long l; } uu;
  488.         uu.f = u.d;
  489.         fprintf (file, "0Fx%08x", uu.l);
  490.       }
  491. #else
  492.       fprintf (file, "0f%.20e", u.d); 
  493. #endif
  494.     }
  495.     }
  496.   else
  497.     {
  498. #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
  499.       if (GET_CODE (x) == CONST_INT)
  500. #endif
  501.     PUT_IMMEDIATE_PREFIX (file);
  502.       output_addr_const (file, x);
  503.     }
  504. }
  505.  
  506. /* PRINT_OPERAND_ADDRESS is defined to call this function,
  507.    which is easier to debug than putting all the code in
  508.    a macro definition in ns32k.h .  */
  509.  
  510. /* Completely rewritten to get this to work with Gas for PC532 Mach.
  511.    This function didn't work and I just wasn't able (nor very willing) to
  512.    figure out how it worked.
  513.    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
  514.  
  515. print_operand_address (file, addr)
  516.      register FILE *file;
  517.      register rtx addr;
  518. {
  519.   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
  520.   rtx offset, base, indexexp, tmp;
  521.   int scale;
  522.   extern int flag_pic;
  523.  
  524.   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
  525.     {
  526.       fprintf (file, "tos");
  527.       return;
  528.     }
  529.  
  530.   offset = NULL;
  531.   base = NULL;
  532.   indexexp = NULL;
  533.   while (addr != NULL)
  534.     {
  535.       if (GET_CODE (addr) == PLUS)
  536.     {
  537.       if (GET_CODE (XEXP (addr, 0)) == PLUS)
  538.         {
  539.           tmp = XEXP (addr, 1);
  540.           addr = XEXP (addr, 0);
  541.         }
  542.       else
  543.         {
  544.           tmp = XEXP (addr,0);
  545.           addr = XEXP (addr,1);
  546.         }
  547.     }
  548.       else
  549.     {
  550.       tmp = addr;
  551.       addr = NULL;
  552.     }
  553.       switch (GET_CODE (tmp))
  554.     {
  555.     case PLUS:
  556.       abort ();
  557.     case MEM:
  558.       if (base)
  559.         {
  560.           indexexp = base;
  561.           base = tmp;
  562.         }
  563.       else
  564.         base = tmp;
  565.       break;
  566.     case REG:
  567.       if (REGNO (tmp) < 8)
  568.         if (base)
  569.           {
  570.         indexexp = tmp;
  571.           }
  572.         else
  573.           base = tmp;
  574.       else
  575.         if (base)
  576.           {
  577.         indexexp = base;
  578.         base = tmp;
  579.           }
  580.         else
  581.           base = tmp;
  582.       break;
  583.     case MULT:
  584.       indexexp = tmp;
  585.       break;
  586.     case SYMBOL_REF:
  587.       if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
  588.           && ! SYMBOL_REF_FLAG (tmp))
  589.         {
  590.           if (base)
  591.         {
  592.           if (indexexp)
  593.             abort ();
  594.           indexexp = base;
  595.         }
  596.           base = tmp;
  597.           break;
  598.         }
  599.     case CONST:
  600.       if (flag_pic && GET_CODE (tmp) == CONST)
  601.         {
  602.           rtx sym, off, tmp1;
  603.           tmp1 = XEXP (tmp,0);
  604.           if (GET_CODE (tmp1)  != PLUS)
  605.         abort ();
  606.  
  607.           sym = XEXP (tmp1,0);
  608.           if (GET_CODE (sym) != SYMBOL_REF)
  609.             {
  610.               off = sym;
  611.           sym = XEXP (tmp1,1);
  612.         }
  613.           else
  614.             off = XEXP (tmp1,1);
  615.           if (GET_CODE (sym) == SYMBOL_REF)
  616.         {
  617.           if (GET_CODE (off) != CONST_INT)
  618.             abort ();
  619.  
  620.           if (CONSTANT_POOL_ADDRESS_P (sym)
  621.               || SYMBOL_REF_FLAG (sym))
  622.             {
  623.               SYMBOL_REF_FLAG (tmp) = 1;
  624.             }
  625.           else
  626.             {
  627.               if (base)
  628.             {
  629.               if (indexexp)
  630.                 abort ();
  631.  
  632.               indexexp = base;
  633.             }
  634.  
  635.               if (offset != 0)
  636.             abort ();
  637.  
  638.               base = sym;
  639.               offset = off;
  640.               break;
  641.             }
  642.         }
  643.         }
  644.     case CONST_INT:
  645.     case LABEL_REF:
  646.       if (offset)
  647.         offset = gen_rtx (PLUS, SImode, tmp, offset);
  648.       else
  649.         offset = tmp;
  650.       break;
  651.     default:
  652.       abort ();
  653.     }
  654.     }
  655.   if (! offset)
  656.     offset = const0_rtx;
  657.  
  658.   if (base
  659. #ifndef INDEX_RATHER_THAN_BASE
  660.       && (flag_pic || TARGET_HIMEM)
  661.       && GET_CODE (base) != SYMBOL_REF 
  662.       && GET_CODE (offset) != CONST_INT
  663. #else
  664.   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
  665. #endif
  666.       && !indexexp && GET_CODE (base) == REG
  667.       && REG_OK_FOR_INDEX_P (base))
  668.     {
  669.       indexexp = base;
  670.       base = NULL;
  671.     }
  672.  
  673.   /* now, offset, base and indexexp are set */
  674. #ifndef BASE_REG_NEEDED
  675.   if (! base)
  676.     {
  677. #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
  678.       if (GET_CODE (offset) == CONST_INT)
  679. #endif
  680.     PUT_ABSOLUTE_PREFIX (file);
  681.     }
  682. #endif
  683.  
  684.   output_addr_const (file, offset);
  685.   if (base) /* base can be (REG ...) or (MEM ...) */
  686.     switch (GET_CODE (base))
  687.       {
  688.     /* now we must output base.  Possible alternatives are:
  689.        (rN)       (REG ...)
  690.        (sp)          (REG ...)
  691.        (fp)       (REG ...)
  692.        (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
  693.        (disp(fp)) (MEM ...)       just before possible [rX:y]
  694.        (disp(sp)) (MEM ...)
  695.        (disp(sb)) (MEM ...)
  696.        */
  697.       case REG:
  698.     fprintf (file, "(%s)", reg_names[REGNO (base)]);
  699.     break;
  700.       case SYMBOL_REF:
  701.     if (! flag_pic)
  702.       abort ();
  703.  
  704.         fprintf (file, "(");
  705.     output_addr_const (file, base);
  706.     fprintf (file, "(sb))");
  707.         break;
  708.       case MEM:
  709.     addr = XEXP(base,0);
  710.     base = NULL;
  711.     offset = NULL;
  712.     while (addr != NULL)
  713.       {
  714.         if (GET_CODE (addr) == PLUS)
  715.           {
  716.         if (GET_CODE (XEXP (addr, 0)) == PLUS)
  717.           {
  718.             tmp = XEXP (addr, 1);
  719.             addr = XEXP (addr, 0);
  720.           }
  721.         else
  722.           {
  723.             tmp = XEXP (addr, 0);
  724.             addr = XEXP (addr, 1);
  725.           }
  726.           }
  727.         else
  728.           {
  729.         tmp = addr;
  730.         addr = NULL;
  731.           }
  732.         switch (GET_CODE (tmp))
  733.           {
  734.           case REG:
  735.         base = tmp;
  736.         break;
  737.           case CONST:
  738.           case CONST_INT:
  739.           case SYMBOL_REF:
  740.           case LABEL_REF:
  741.         if (offset)
  742.           offset = gen_rtx (PLUS, SImode, tmp, offset);
  743.         else
  744.           offset = tmp;
  745.         break;
  746.           default:
  747.         abort ();
  748.           }
  749.       }
  750.     if (! offset)
  751.       offset = const0_rtx;
  752.     fprintf (file, "(");
  753.     output_addr_const (file, offset);
  754.     if (base)
  755.       fprintf (file, "(%s)", reg_names[REGNO (base)]);
  756.     else if (TARGET_SB)
  757.       fprintf (file, "(sb)");
  758.     else
  759.       abort ();
  760.     fprintf (file, ")");
  761.     break;
  762.       default:
  763.     abort ();
  764.       }
  765. #ifdef PC_RELATIVE
  766.   else if (GET_CODE (offset) != CONST_INT)
  767.     fprintf (file, "(pc)");
  768. #ifdef BASE_REG_NEEDED
  769.   else if (TARGET_SB)
  770.     fprintf (file, "(sb)");
  771.   else
  772.     abort ();
  773. #endif
  774. #endif /* PC_RELATIVE */
  775.  
  776.   /* now print index if we have one */
  777.   if (indexexp)
  778.     {
  779.       if (GET_CODE (indexexp) == MULT)
  780.     {
  781.       scale = INTVAL (XEXP (indexexp, 1)) >> 1;
  782.       indexexp = XEXP (indexexp, 0);
  783.     }
  784.       else
  785.     scale = 0;
  786.       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
  787.     abort ();
  788.  
  789. #ifdef UTEK_ASM
  790.       fprintf (file, "[%c`%s]",
  791.            scales[scale],
  792.            reg_names[REGNO (indexexp)]);
  793. #else
  794.       fprintf (file, "[%s:%c]",
  795.            reg_names[REGNO (indexexp)],
  796.            scales[scale]);
  797. #endif
  798.     }
  799. }
  800.  
  801. /* National 32032 shifting is so bad that we can get
  802.    better performance in many common cases by using other
  803.    techniques.  */
  804. char *
  805. output_shift_insn (operands)
  806.      rtx *operands;
  807. {
  808.   if (GET_CODE (operands[2]) == CONST_INT
  809.       && INTVAL (operands[2]) > 0
  810.       && INTVAL (operands[2]) <= 3)
  811.     if (GET_CODE (operands[0]) == REG)
  812.       {
  813.     if (GET_CODE (operands[1]) == REG)
  814.       {
  815.         if (REGNO (operands[0]) == REGNO (operands[1]))
  816.           {
  817.         if (operands[2] == const1_rtx)
  818.           return "addd %0,%0";
  819.         else if (INTVAL (operands[2]) == 2)
  820.           return "addd %0,%0\n\taddd %0,%0";
  821.           }
  822.         if (operands[2] == const1_rtx)
  823.           return "movd %1,%0\n\taddd %0,%0";
  824.         
  825.         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  826.         return "addr %a1,%0";
  827.       }
  828.     if (operands[2] == const1_rtx)
  829.       return "movd %1,%0\n\taddd %0,%0";
  830.       }
  831.     else if (GET_CODE (operands[1]) == REG)
  832.       {
  833.     operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  834.     return "addr %a1,%0";
  835.       }
  836.     else if (INTVAL (operands[2]) == 1
  837.          && GET_CODE (operands[1]) == MEM
  838.          && rtx_equal_p (operands [0], operands[1]))
  839.       {
  840.     rtx temp = XEXP (operands[1], 0);
  841.     
  842.     if (GET_CODE (temp) == REG
  843.         || (GET_CODE (temp) == PLUS
  844.         && GET_CODE (XEXP (temp, 0)) == REG
  845.         && GET_CODE (XEXP (temp, 1)) == CONST_INT))
  846.       return "addd %0,%0";
  847.       }
  848.     else return "ashd %2,%0";
  849.   return "ashd %2,%0";
  850. }
  851.  
  852. char *
  853. output_move_dconst (n, s)
  854.     int n;
  855.     char *s;
  856. {
  857.   static char r[32];
  858.  
  859.   if (n > -9 && n < 8)
  860.     strcpy (r, "movqd ");
  861.   else if (n > 0 && n < 256)
  862.     strcpy (r, "movzbd ");
  863.   else if (n > 0 && n < 65536)
  864.     strcpy (r, "movzwd ");
  865.   else if (n < 0 && n > -129)
  866.     strcpy (r, "movxbd ");
  867.   else if (n < 0 && n > -32769)
  868.     strcpy (r, "movxwd ");
  869.   else
  870.     strcpy (r, "movd ");
  871.   strcat (r, s);
  872.   return r;
  873. }
  874.